﻿using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using OpenAiClient.Util.GZip;
using OpenAiClient.Util.IO;
using OpenAiClient.Util.Xml;

namespace OpenAiClient.Services
{
    public class ConfigService : IConfigService
    {
        public string WebApiUrl => $@"http://{ServerIp}:{ServerPort}";
        public string ServerIp { get; private set; } = string.Empty;
        public int ServerPort { get; private set; }
        public int RequestTimeout { get; private set; }
        public string ApiKey { get; private set; } = string.Empty;
        public string AccountId { get; set; } = string.Empty;
        public string AesKey { get; private set; } = string.Empty;

        /// <summary>
        /// APP数据文件夹
        /// </summary>
        public string AppDataDirectory { get; }

        private string _configName = string.Empty;

        private readonly ILogService _logService;

        public ConfigService(ILogService logService)
        {
            _logService = logService;

            //APP数据文件夹
            var path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            var app = typeof(ConfigService).Namespace?.Split('.').FirstOrDefault();
            AppDataDirectory = Path.Combine(path, app ?? string.Empty);

            //创建文件夹
            CreateDirectory(AppDataDirectory);
        }

        private void CreateDirectory(string path)
        {
            if (!Directory.Exists(path))
            {
                try
                {
                    Directory.CreateDirectory(path);
                }
                catch (Exception e)
                {
                    _logService.Error($"创建文件夹{path}失败：{e.Message}.");
                }
            }
        }

        #region 加载参数

        public void LoadConfig(string configName)
        {
            _configName = configName;

            //Get Config file
            var info = new DirectoryInfo(Assembly.GetExecutingAssembly().Location);
            var xmlFilePath = Path.Combine(info.Parent?.FullName ?? string.Empty, _configName);

            //从配置文件读取数据
            var xmlDoc = new XmlDocument();
            try
            {
                xmlDoc.Load(xmlFilePath);
            }
            catch (Exception e)
            {
                _logService.Error($@"加载配置文件[{configName}]失败：{e.Message}.");
                return;
            }

            var root = xmlDoc.SelectSingleNode("/AppSettings");
            LoadAesKey(); //加载AesKey
            LoadServerConfig(root); //加载服务器参数
            LoadSdkConfig(root); //加载SDK参数
        }

        private void LoadAesKey()
        {
            try
            {
                var fileName = Path.Combine(Environment.CurrentDirectory, @"AesKey.bin");
                var content = FileHelper.GetFileContent(fileName);
                AesKey = GZipHelper.GZipDecompressString(content);
            }
            catch (Exception e)
            {
                _logService.Error($@"加载AesKey异常：{e.Message}.");
            }
        }

        private void LoadServerConfig(XmlNode? root)
        {
            try
            {
                var node = root?.SelectSingleNode("Server");
                if (XmlHelper.GetNodeAttributeStr(node, "Ip", out var ip) &&
                    XmlHelper.GetNodeAttributeInt(node, "Port", out var port) &&
                    XmlHelper.GetNodeAttributeInt(node, "RequestTimeout", out var requestTimeout))
                {
                    ServerIp = ip;
                    ServerPort = port;
                    RequestTimeout = requestTimeout;
                }
            }
            catch (Exception e)
            {
                _logService.Error($@"加载服务器参数异常：{e.Message}.");
            }
        }

        private void LoadSdkConfig(XmlNode? root)
        {
            try
            {
                var node = root?.SelectSingleNode("Sdk");
                if (XmlHelper.GetNodeAttributeStr(node, "ApiKey", out var apiKey))
                {
                    ApiKey = apiKey;
                }
            }
            catch (Exception e)
            {
                _logService.Error($@"加载Sdk参数异常：{e.Message}.");
            }
        }

        #endregion

        #region 设置参数

        public void SetServerPara(string ip, int port, int requestTimeout)
        {
            if (string.IsNullOrWhiteSpace(ip) || port <= 0 || requestTimeout <= 0)
            {
                throw new ArgumentException("SetServerPara invalid argument");
            }

            ServerIp = ip;
            ServerPort = port;
            RequestTimeout = requestTimeout;

            //Get Config file
            var info = new DirectoryInfo(Assembly.GetExecutingAssembly().Location);
            var xmlFilePath = Path.Combine(info.Parent?.FullName ?? string.Empty, _configName);

            //从配置文件读取数据
            var xmlDoc = new XmlDocument();
            try
            {
                xmlDoc.Load(xmlFilePath);
                var node = xmlDoc.SelectSingleNode("/AppSettings/Server");
                XmlHelper.SetNodeAttributeValue(node, "Ip", ip);
                XmlHelper.SetNodeAttributeValue(node, "Port", $"{port}");
                XmlHelper.SetNodeAttributeValue(node, "RequestTimeout", $"{RequestTimeout}");
                xmlDoc.Save(xmlFilePath);
            }
            catch (Exception e)
            {
                _logService.Error($@"设置服务器参数失败：{e.Message}.");
            }
        }

        public void SetSdkPara(string apiKey)
        {
            ApiKey = apiKey;

            //Get Config file
            var info = new DirectoryInfo(Assembly.GetExecutingAssembly().Location);
            var xmlFilePath = Path.Combine(info.Parent?.FullName ?? string.Empty, _configName);

            //从配置文件读取数据
            var xmlDoc = new XmlDocument();
            try
            {
                xmlDoc.Load(xmlFilePath);
                var node = xmlDoc.SelectSingleNode("/AppSettings/Sdk");
                XmlHelper.SetNodeAttributeValue(node, "ApiKey", apiKey);
                xmlDoc.Save(xmlFilePath);
            }
            catch (Exception e)
            {
                _logService.Error($@"设置Sdk参数失败：{e.Message}.");
            }
        }

        #endregion
    }
}
